package com.bc.bcapi.service;

import com.bc.bccore.util.DateUtil;
import com.bc.bcmodel.domain.T_SequenceModelExt;
import com.bc.commoncore.util.JsonUtil;
import com.bc.commonentity.common.SequenceRange;
import com.bc.commonentity.enums.SeqNameEnum;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.math.BigInteger;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import com.bc.bcapi.dao.T_SequenceMapper;
import com.bc.bcmodel.domain.T_SequenceModel;

/**
 * @Name T_SequenceService * @Description TODO * @Author generation * @Date 2018/8/9 15:56:31 * @Version 1.0
 **/
@Service
public class T_SequenceService {
    private final static Logger logger = LoggerFactory.getLogger(T_SequenceService.class);
    /**
     * 获取sequence重试次数
     */
    private static final int retryTimes = 10;
    private final Map<String, SequenceRange> seqMap = new ConcurrentHashMap<String, SequenceRange>();
    private final Lock lock = new ReentrantLock();
    @Resource
    T_SequenceMapper t_SequenceMapper;

    /**
     * 生成流水号
     *
     * @param seqName
     * @return
     */
    
    public String genSequence(SeqNameEnum seqName) {
        String sequenceId = aligningSequenceId(String.valueOf(nextValue(seqName.getDesc())));
        if (StringUtils.equals(seqName.getType(), "D")) {
            return getNowDatePrefix() + sequenceId;
        } else if (StringUtils.equals(seqName.getType(), "P")) {
            return seqName.getType() + getNowDatePrefix() + sequenceId;
        } else {
            String seq = seqName.getType() + sequenceId;
            return seq;
        }
    }

    private String aligningSequenceId(String sequenceId) {
        return StringUtils.substring("000000000", StringUtils.length(sequenceId)) + sequenceId;
    }

    /**
     * 使用时间(8位长度)最为ID的前缀
     *
     * @return
     */
    private String getNowDatePrefix() {
        return DateUtil.formatShort(new Date());
    }

    private long nextValue(String tableName) {
        SequenceRange sequenceRange = null;
        if (null == (sequenceRange = seqMap.get(tableName))) {
            lock.lock();
            try {
                if (null == (sequenceRange = seqMap.get(tableName))) {
                    sequenceRange = nextRange(tableName);
                    seqMap.put(tableName, sequenceRange);
                }
            } finally {
                lock.unlock();
            }
        }

        if (null == sequenceRange) {
            throw new IllegalArgumentException("获取序列失败tableName=" + tableName);
        }

        long value = sequenceRange.getAndIncrement();
        if (-1 == value) {
            lock.lock();
            try {
                sequenceRange = seqMap.get(tableName);//获取最新值
                value = sequenceRange.getAndIncrement();//获取一次sequence
                if (value == -1) {
                    while (true) {
                        if (sequenceRange.isOver()) {
                            sequenceRange = nextRange(tableName);
                            seqMap.put(tableName, sequenceRange);//将最新range放到map
                        }
                        value = sequenceRange.getAndIncrement();
                        if (-1 == value) {
                            continue;
                        }
                        break;
                    }
                }
            } finally {
                lock.unlock();
            }
        }

        if (logger.isInfoEnabled()) {
            logger.info("create new sequende :[" + value + "]");
        }

        return value;
    }

    private SequenceRange nextRange(String name) throws IllegalArgumentException {
        if (StringUtils.isBlank(name)) {
            throw new IllegalArgumentException("prarams is blank. name=[" + name + "]");
        }

        for (int i = 0; i < retryTimes; i++) {
            try {
                T_SequenceModel querySeqModel = new T_SequenceModel();
                querySeqModel.setSeq_name(name);
                T_SequenceModelExt sequenceDO = new T_SequenceModelExt(findByNamedParam(querySeqModel));
                if (null == sequenceDO) {
                    throw new IllegalArgumentException("can't get sequence. tableName=[" + name
                            + "]");
                }

                T_SequenceModelExt updateSeqModel = new T_SequenceModelExt();
                updateSeqModel.setId(sequenceDO.getId());
                updateSeqModel.setSeq_name(sequenceDO.getSeq_name());
                updateSeqModel.setOld_seq_value(sequenceDO.getSeq_value());
                updateSeqModel.setSeq_value(new BigInteger(String.valueOf(sequenceDO.newSeqValue())));

                int updateResult = updateExt(updateSeqModel);
                if (0 == updateResult) {
                    logger.warn("获取序列号失败，更新区间失败，tableName=" + name);
                    continue;
                }

                return new SequenceRange(sequenceDO.newSeqValue() - sequenceDO.getStep().longValue() + 1,
                        sequenceDO.newSeqValue());
            } catch (Exception e) {
                logger.warn("获取序列号异常，tableName=" + name, e);
                continue;
            }
        }

        throw new IllegalArgumentException("获取序列失败，tableName=" + name);
    }

    /**
     * 保存单条数据     *      * @return
     */
    
    public int insert(T_SequenceModel req) {
        return t_SequenceMapper.insert(req);
    }

    /**
     * 批量增加数据     *      * @return
     */
    
    public int insertBatch(List<T_SequenceModel> req) {
        return t_SequenceMapper.insertBatch(req);
    }

    /**
     * 根据对象属性查找满足条件的第一条数据     *      * @return
     */
    
    public T_SequenceModel findByNamedParam(T_SequenceModel req) {
        return t_SequenceMapper.findByNamedParam(req);
    }

    /**
     * 根据对象查询所有数据     *      * @return
     */
    
    public List<T_SequenceModel> getAllList(T_SequenceModel req) {
        return t_SequenceMapper.findByNamedParamList(req);
    }

    /**
     * 根据对象查询所有分页数据     *      * @return
     */
    
    public PageInfo<T_SequenceModel> getList(T_SequenceModel req) {
        PageHelper.startPage(req.getPage_index(), req.getPage_size());
        List<T_SequenceModel> list = t_SequenceMapper.findByNamedParamList(req);
        return new PageInfo<T_SequenceModel>(list);
    }

    /**
     * 更新指定对象     *      * @return
     */
    
    public int update(T_SequenceModel req) {
        return t_SequenceMapper.update(req);
    }

    /**
     * 删除指定数据     *      * @return
     */
    
    public int delete(BigInteger id) {
        return t_SequenceMapper.delete(id);
    }

    /**
     * 根据条件统计数据量     *      * @return
     */
    
    public long count(T_SequenceModel req) {
        return t_SequenceMapper.count(req);
    }

    
    public int updateExt(T_SequenceModelExt req) {
        return t_SequenceMapper.updateExt(req);
    }

}